package com.dg.gaming.api.common.util;

import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import java.util.zip.*;
import java.util.*;

public class TestDigestGenerator {
    static private final char[] digits = {'0', '1', '2', '3', '4', '5', '6',
                                         '7', '8', '9', 'A', 'B', 'C', 'D', 'E',
                                         'F'};
    public enum CheckSumAlgorithm {
        Adler32, CRC32
    }


    public enum MessageDigestAlgorithm {
        MD5, SHA
    }


    /**
     * based on sun link
     * https://java.sun.com/j2se/1.4.2/docs/guide/security/jce/JCERefGuide.html#AppA
     * DESede is Tripple DES algorithm
     *
     * @author xakn1
     *
     */
    public enum EncryptionAlgorithm {
        DES, SHA, DESede, RC2, RC4, RC5
    }


    public enum EncryptionMode {
        NONE, CBC, CFB, ECB, OFB, PCBC
    }


    public enum EncryptionPadding {
        NoPadding, PKCS5Padding, SSL3Padding
    }


    /**
     *
     * @param input
     * @param alogorithm
     *            e.g MD5, SHA algorithms
     */
    public static void computeDigest(String input,
                                     MessageDigestAlgorithm alogorithm) {

        // Generate Des key and vector using MD5, SHA
        MessageDigest msgdig;
        try {
            msgdig = MessageDigest.getInstance(alogorithm.name());
        } catch (NoSuchAlgorithmException e) {
            System.err.println(
                    "Exception while creating instance of Message digest class. Exception:" +
                    e);
            throw new RuntimeException(e);
        }

        msgdig.update(input.getBytes());
        byte[] mdbytes = msgdig.digest();

//        System.out.println(alogorithm.name() + " hash key string (in hex):: " +
//                           hexEncode(mdbytes));

    }

    /**
     *
     * @param input
     * @param algorthm
     * @return
     */
    public static long computeCheckSum(String input,
                                       CheckSumAlgorithm algorithm) {
        long sum = -1;

        Checksum cs = null;

        if (algorithm.equals(CheckSumAlgorithm.Adler32)) {
            cs = new Adler32();
        } else if (algorithm.equals(CheckSumAlgorithm.CRC32)) {
            cs = new CRC32();
        }

        cs.update(input.getBytes(), 0, input.length());
        sum = cs.getValue();

//        System.out.println(algorithm.name() + " has a sum of " + sum);

        return sum;
    }

    /**
     * hexEncode is create String object which contains hex representation of
     * data present in bytes array
     *
     * @param bytes -
     *            input array of bytes to be hex coded
     * @return String objecting containing hex representation of bytes in input
     *         array
     */
    public static String hexEncode(byte[] bytes) {
        StringBuffer buffer = new StringBuffer(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            byte byteValue = bytes[i];
            buffer.append(digits[(byteValue & 0xf0) >> 4]);
            buffer.append(digits[byteValue & 0x0f]);
        }
        return buffer.toString();
    }

    /**
     *
     * @param clearText
     * @param cipher
     * @param secretKey
     * @param ivVector
     *            Initialization Vector
     * @return
     * @throws PAPException
     */
    public static byte[] encrypt(String clearText, Cipher cipher,
                                 SecretKey secretKey, IvParameterSpec ivVector) throws
            Exception {

        byte[] ciphertext = null;
        try {
            cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivVector);
            ciphertext = cipher.doFinal(clearText.getBytes());
        } catch (Exception e) {
            System.err.println("Exception while encrypting data:" + clearText +
                               " Exception:" + e);
            throw new RuntimeException(e);
        }
//
//        System.out.print("Encrypt -> Data - " + clearText +
//                         " is encoded as --> " + hexEncode(ciphertext));

        return ciphertext;
    }

    /**
     *
     * @param cipherText
     * @param cipher
     * @param secretKey
     * @param ivVector
     * @return
     * @throws PAPException
     */
    public static String decrypt(byte[] cipherText, Cipher cipher,
                                 SecretKey secretKey, IvParameterSpec ivVector) throws
            Exception {
        byte[] cleartext = null;
        try {
            cipher.init(Cipher.DECRYPT_MODE, secretKey, ivVector);
            cleartext = cipher.doFinal(cipherText);
        } catch (Exception e) {
            System.err.println("Exception while decrypting data:" +
                               hexEncode(cipherText) + " Exception:" + e);
            throw new RuntimeException(e);
        }
//
//        System.out.println("Decrypt -> Data - " + hexEncode(cipherText) +
//                           " is encoded as --> " + new String(cleartext));

        return new String(cleartext);
    }

    /**
     * @param args
     */




    public static void main(String[] args) throws Exception {
        computeDigest("SecretWord", MessageDigestAlgorithm.MD5);
        computeDigest("SecretWord", MessageDigestAlgorithm.SHA);

        computeCheckSum("SecretWord", CheckSumAlgorithm.Adler32);
        computeCheckSum("SecretWord", CheckSumAlgorithm.CRC32);

        //-------------- Testing encryption & decryption --------------

        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        byte[] bt = new byte[24];
        random.nextBytes(bt);

        String secret = "sdfsdf";
        String input =
                "<join_table userid=\"1\" table=\"1\" username=\"dito\"/>";
        byte[] iv = new byte[] {(byte) 0x8E, 0x12, 0x39, (byte) 0x9C, 0x07,
                    0x72, 0x6F, 0x5A};
        //uses the first 24 bytes in the secret
        DESedeKeySpec keyspec = new DESedeKeySpec(bt);
        SecretKeyFactory keyfactory = SecretKeyFactory.getInstance(
                EncryptionAlgorithm.DESede.name());
        SecretKey deskey = keyfactory.generateSecret(keyspec);

        // Create an 8-byte initialization vector


        IvParameterSpec ivVector = new IvParameterSpec(iv);
        Cipher cipher = Cipher.getInstance(EncryptionAlgorithm.DESede.name() +
                                           "/" + EncryptionMode.CBC.name() +
                                           "/"
                                           +
                                           EncryptionPadding.PKCS5Padding.name());

        byte[] cipherText = encrypt(input, cipher, deskey, ivVector);

        System.out.println("Encrypted Text = " + hexEncode(cipherText));
        System.out.println(" size=" + cipherText.length);
        keyspec = new DESedeKeySpec(bt);
        keyfactory = SecretKeyFactory.getInstance(
                EncryptionAlgorithm.DESede.name());
        deskey = keyfactory.generateSecret(keyspec);

        // Create an 8-byte initialization vector


        ivVector = new IvParameterSpec(iv);
        cipher = Cipher.getInstance(EncryptionAlgorithm.DESede.name() +
                                    "/" + EncryptionMode.CBC.name() +
                                    "/"
                                    +
                                    EncryptionPadding.PKCS5Padding.name());
        String clearText = decrypt(cipherText, cipher, deskey, ivVector);

        System.out.println("Clear Text = " + clearText + " size=" +
                           clearText.length());

    }
}
